Modelo

source("../../lib/som-utils.R")

Attaching package: 'dplyr'
The following objects are masked from 'package:stats':

    filter, lag
The following objects are masked from 'package:base':

    intersect, setdiff, setequal, union
source("../../lib/maps-utils.R")
Linking to GEOS 3.8.0, GDAL 3.0.4, PROJ 6.3.1

Carga del modelo desde disco

mpr.set_base_path_analysis()
model <- mpr.load_model("som-305.rds.xz")
summary(model)
SOM of size 5x5 with a hexagonal topology and a bubble neighbourhood function.
The number of data layers is 1.
Distance measure(s) used: sumofsquares.
Training data included: 94881 objects.
Mean distance to the closest unit in the map: 0.464.
plot(model, type="changes")

Carga del dataset de entrada

df <- mpr.load_data("datos_mes.csv.xz")
df
summary(df)
 id_estacion           fecha             fecha_cnt           tmax      
 Length:94881       Length:94881       Min.   : 1.000   Min.   :-53.0  
 Class :character   Class :character   1st Qu.: 4.000   1st Qu.:148.0  
 Mode  :character   Mode  :character   Median : 6.000   Median :198.0  
                                       Mean   : 6.497   Mean   :200.2  
                                       3rd Qu.: 9.000   3rd Qu.:255.0  
                                       Max.   :12.000   Max.   :403.0  
      tmin             precip           nevada           prof_nieve      
 Min.   :-121.00   Min.   :  0.00   Min.   :0.000000   Min.   :   0.000  
 1st Qu.:  53.00   1st Qu.:  3.00   1st Qu.:0.000000   1st Qu.:   0.000  
 Median :  98.00   Median : 10.00   Median :0.000000   Median :   0.000  
 Mean   :  98.86   Mean   : 16.25   Mean   :0.000295   Mean   :   0.467  
 3rd Qu.: 148.00   3rd Qu.: 22.00   3rd Qu.:0.000000   3rd Qu.:   0.000  
 Max.   : 254.00   Max.   :422.00   Max.   :6.000000   Max.   :1834.000  
    longitud        latitud            altitud      
 Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:38.28   1st Qu.: -5.6417   1st Qu.:  42.0  
 Median :40.82   Median : -3.4500   Median : 247.0  
 Mean   :39.66   Mean   : -3.4350   Mean   : 418.5  
 3rd Qu.:42.08   3rd Qu.:  0.4914   3rd Qu.: 656.0  
 Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  

Carga de los mapas

world <- ne_countries(scale = "medium", returnclass = "sf")
spain <- subset(world, admin == "Spain")

Mapa de densidad

plot(model, type="count", shape = "straight", palette.name = mpr.degrade.bleu)

NĂºmero de elementos en cada celda:

nb <- table(model$unit.classif)
print(nb)

   1    2    3    4    5    6    7    8    9   10   11   12   13   14   15   16 
1198  934 6552 3322 1573 4763 3868 4940 2610 4796 3787 3645 2877 3549 3895 4939 
  17   18   19   20   21   22   23   24   25 
5157 2558 3094 5623 5434 5107 1383 3830 5447 

ComprobaciĂ³n de nodos vacĂ­os:

dim_model <- 5*5;
len_nb = length(nb);
empty_nodes <- dim_model != len_nb;
if (empty_nodes) {
  print(paste("[Warning] Existen nodos vacĂ­os: ", len_nb, "/", dim_model))
}

Mapa de distancia entre vecinos

plot(model, type="dist.neighbours", shape = "straight")

Influencia de las variables

model_colnames = c("tmax", "tmin", "longitud", "latitud", "altitud")
model_ncol = length(model_colnames)

Mapa de variables.

plot(model, shape = "straight")

Mapa de calor por variable

par(mfrow=c(3,4))
for (j in 1:model_ncol) {
  plot(model, type="property", property=getCodes(model,1)[,j],
    palette.name=mpr.coolBlueHotRed,
    main=model_colnames[j],
    cex=0.5, shape = "straight")
}

CorrelaciĂ³n para cada columna del vector de nodos

if (!empty_nodes) {
  cor <- apply(getCodes(model,1), 2, mpr.weighted.correlation, w=nb, som=model)
  print(cor)
}
           tmax       tmin  longitud   latitud     altitud
[1,] -0.6649573 -0.6893387 0.5222588 0.4671490  0.08973551
[2,]  0.3970066  0.2978972 0.3021099 0.4289892 -0.19243238

RepresentaciĂ³n de cada variable en un mapa de factores:

if (!empty_nodes) {
  par(mfrow=c(1,1))
  plot(cor[1,], cor[2,], xlim=c(-1,1), ylim=c(-1,1), type="n")
  lines(c(-1,1),c(0,0))
  lines(c(0,0),c(-1,1))
  text(cor[1,], cor[2,], labels=model_colnames, cex=0.75)
  symbols(0,0,circles=1,inches=F,add=T)
}

Importancia de cada variable - varianza ponderada por el tamaño de la celda:

if (!empty_nodes) {
  sigma2 <- sqrt(apply(getCodes(model,1),2,function(x,effectif)
     {m<-sum(effectif*(x-weighted.mean(x,effectif))^2)/(sum(effectif)-1)},
     effectif=nb))
  print(sort(sigma2,decreasing=T))
}
 longitud   altitud   latitud      tmax      tmin 
0.9692537 0.9556302 0.9545084 0.9515501 0.9451555 

Clustering

if (!empty_nodes) {
  hac <- mpr.hac(model, nb)
}

VisualizaciĂ³n de 3 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=3)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=3)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt          tmax            tmin           precip            nevada 
 Min.   : 1.00   Min.   : 13.0   Min.   :-33.0   Min.   :  0.000   Min.   :0  
 1st Qu.: 4.00   1st Qu.:200.0   1st Qu.:132.0   1st Qu.:  0.000   1st Qu.:0  
 Median : 7.00   Median :225.0   Median :160.0   Median :  1.000   Median :0  
 Mean   : 6.51   Mean   :217.2   Mean   :150.4   Mean   :  7.421   Mean   :0  
 3rd Qu.: 9.00   3rd Qu.:253.0   3rd Qu.:189.0   3rd Qu.:  8.000   3rd Qu.:0  
 Max.   :12.00   Max.   :356.0   Max.   :244.0   Max.   :309.000   Max.   :0  
   prof_nieve          longitud        latitud          altitud      
 Min.   : 0.00000   Min.   :27.82   Min.   :-17.89   Min.   :  14.0  
 1st Qu.: 0.00000   1st Qu.:28.31   1st Qu.:-16.50   1st Qu.:  25.0  
 Median : 0.00000   Median :28.44   Median :-16.33   Median :  35.0  
 Mean   : 0.03075   Mean   :28.37   Mean   :-16.05   Mean   : 520.9  
 3rd Qu.: 0.00000   3rd Qu.:28.48   3rd Qu.:-15.39   3rd Qu.: 632.0  
 Max.   :46.00000   Max.   :28.95   Max.   :-13.60   Max.   :2371.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt           tmax            tmin             precip      
 Min.   : 1.000   Min.   :-53.0   Min.   :-121.00   Min.   :  0.00  
 1st Qu.: 2.000   1st Qu.:125.0   1st Qu.:  31.00   1st Qu.:  6.00  
 Median : 4.000   Median :159.0   Median :  62.00   Median : 14.00  
 Mean   : 5.937   Mean   :156.1   Mean   :  59.91   Mean   : 20.22  
 3rd Qu.:11.000   3rd Qu.:189.0   3rd Qu.:  89.00   3rd Qu.: 28.00  
 Max.   :12.000   Max.   :306.0   Max.   : 207.00   Max.   :371.00  
     nevada           prof_nieve           longitud        latitud       
 Min.   :0.000000   Min.   :   0.0000   Min.   :35.28   Min.   :-8.6494  
 1st Qu.:0.000000   1st Qu.:   0.0000   1st Qu.:38.99   1st Qu.:-5.3456  
 Median :0.000000   Median :   0.0000   Median :41.11   Median :-2.9056  
 Mean   :0.000504   Mean   :   0.7917   Mean   :40.59   Mean   :-2.5904  
 3rd Qu.:0.000000   3rd Qu.:   0.0000   3rd Qu.:42.33   3rd Qu.: 0.4914  
 Max.   :6.000000   Max.   :1834.0000   Max.   :43.57   Max.   : 4.2156  
    altitud    
 Min.   :   1  
 1st Qu.:  58  
 Median : 353  
 Mean   : 473  
 3rd Qu.: 704  
 Max.   :2535  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt           tmax            tmin           precip           nevada 
 Min.   : 1.000   Min.   :164.0   Min.   : 54.0   Min.   :  0.00   Min.   :0  
 1st Qu.: 6.000   1st Qu.:241.0   1st Qu.:129.0   1st Qu.:  1.00   1st Qu.:0  
 Median : 7.000   Median :273.0   Median :153.0   Median :  6.00   Median :0  
 Mean   : 7.453   Mean   :272.1   Mean   :154.6   Mean   : 11.33   Mean   :0  
 3rd Qu.: 9.000   3rd Qu.:301.0   3rd Qu.:179.0   3rd Qu.: 15.00   3rd Qu.:0  
 Max.   :12.000   Max.   :403.0   Max.   :254.0   Max.   :422.00   Max.   :0  
   prof_nieve          longitud        latitud           altitud      
 Min.   : 0.00000   Min.   :35.28   Min.   :-8.6494   Min.   :   1.0  
 1st Qu.: 0.00000   1st Qu.:38.95   1st Qu.:-4.6800   1st Qu.:  42.0  
 Median : 0.00000   Median :40.84   Median :-2.0392   Median : 127.0  
 Mean   : 0.00364   Mean   :40.49   Mean   :-2.1999   Mean   : 303.5  
 3rd Qu.: 0.00000   3rd Qu.:41.98   3rd Qu.: 0.5706   3rd Qu.: 582.0  
 Max.   :35.00000   Max.   :43.57   Max.   : 4.2156   Max.   :1894.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

VisualizaciĂ³n de 4 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=4)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=4)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt          tmax            tmin           precip            nevada 
 Min.   : 1.00   Min.   : 13.0   Min.   :-33.0   Min.   :  0.000   Min.   :0  
 1st Qu.: 4.00   1st Qu.:200.0   1st Qu.:132.0   1st Qu.:  0.000   1st Qu.:0  
 Median : 7.00   Median :225.0   Median :160.0   Median :  1.000   Median :0  
 Mean   : 6.51   Mean   :217.2   Mean   :150.4   Mean   :  7.421   Mean   :0  
 3rd Qu.: 9.00   3rd Qu.:253.0   3rd Qu.:189.0   3rd Qu.:  8.000   3rd Qu.:0  
 Max.   :12.00   Max.   :356.0   Max.   :244.0   Max.   :309.000   Max.   :0  
   prof_nieve          longitud        latitud          altitud      
 Min.   : 0.00000   Min.   :27.82   Min.   :-17.89   Min.   :  14.0  
 1st Qu.: 0.00000   1st Qu.:28.31   1st Qu.:-16.50   1st Qu.:  25.0  
 Median : 0.00000   Median :28.44   Median :-16.33   Median :  35.0  
 Mean   : 0.03075   Mean   :28.37   Mean   :-16.05   Mean   : 520.9  
 3rd Qu.: 0.00000   3rd Qu.:28.48   3rd Qu.:-15.39   3rd Qu.: 632.0  
 Max.   :46.00000   Max.   :28.95   Max.   :-13.60   Max.   :2371.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt           tmax          tmin             precip      
 Min.   : 1.000   Min.   : -4   Min.   :-110.00   Min.   :  0.00  
 1st Qu.: 2.000   1st Qu.:129   1st Qu.:  33.00   1st Qu.:  5.00  
 Median : 4.000   Median :161   Median :  64.00   Median : 14.00  
 Mean   : 5.903   Mean   :160   Mean   :  62.34   Mean   : 19.45  
 3rd Qu.:11.000   3rd Qu.:190   3rd Qu.:  90.00   3rd Qu.: 26.00  
 Max.   :12.000   Max.   :306   Max.   : 207.00   Max.   :371.00  
     nevada           prof_nieve          longitud        latitud       
 Min.   :0.000000   Min.   : 0.00000   Min.   :35.28   Min.   :-8.6494  
 1st Qu.:0.000000   1st Qu.: 0.00000   1st Qu.:38.95   1st Qu.:-5.4981  
 Median :0.000000   Median : 0.00000   Median :40.96   Median :-2.9553  
 Mean   :0.000532   Mean   : 0.07726   Mean   :40.51   Mean   :-2.7233  
 3rd Qu.:0.000000   3rd Qu.: 0.00000   3rd Qu.:42.24   3rd Qu.: 0.3664  
 Max.   :6.000000   Max.   :75.00000   Max.   :43.57   Max.   : 4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.:  47.0  
 Median : 286.0  
 Mean   : 382.2  
 3rd Qu.: 667.0  
 Max.   :1405.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt           tmax             tmin             precip      
 Min.   : 1.000   Min.   :-53.00   Min.   :-121.00   Min.   :  0.00  
 1st Qu.: 4.000   1st Qu.: 32.00   1st Qu.: -30.00   1st Qu.: 16.00  
 Median : 7.000   Median : 80.00   Median :  13.00   Median : 29.00  
 Mean   : 6.548   Mean   : 87.82   Mean   :  16.78   Mean   : 33.94  
 3rd Qu.:10.000   3rd Qu.:141.00   3rd Qu.:  64.00   3rd Qu.: 46.00  
 Max.   :12.000   Max.   :257.00   Max.   : 147.00   Max.   :180.00  
     nevada    prof_nieve        longitud        latitud           altitud    
 Min.   :0   Min.   :   0.0   Min.   :40.78   Min.   :-4.0103   Min.   :1405  
 1st Qu.:0   1st Qu.:   0.0   1st Qu.:40.78   1st Qu.:-4.0103   1st Qu.:1894  
 Median :0   Median :   0.0   Median :42.38   Median : 0.8842   Median :2143  
 Mean   :0   Mean   :  13.5   Mean   :41.94   Mean   :-0.2252   Mean   :2089  
 3rd Qu.:0   3rd Qu.:   0.0   3rd Qu.:42.53   3rd Qu.: 1.5242   3rd Qu.:2316  
 Max.   :0   Max.   :1834.0   Max.   :42.77   Max.   : 2.4378   Max.   :2535  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt           tmax            tmin           precip           nevada 
 Min.   : 1.000   Min.   :164.0   Min.   : 54.0   Min.   :  0.00   Min.   :0  
 1st Qu.: 6.000   1st Qu.:241.0   1st Qu.:129.0   1st Qu.:  1.00   1st Qu.:0  
 Median : 7.000   Median :273.0   Median :153.0   Median :  6.00   Median :0  
 Mean   : 7.453   Mean   :272.1   Mean   :154.6   Mean   : 11.33   Mean   :0  
 3rd Qu.: 9.000   3rd Qu.:301.0   3rd Qu.:179.0   3rd Qu.: 15.00   3rd Qu.:0  
 Max.   :12.000   Max.   :403.0   Max.   :254.0   Max.   :422.00   Max.   :0  
   prof_nieve          longitud        latitud           altitud      
 Min.   : 0.00000   Min.   :35.28   Min.   :-8.6494   Min.   :   1.0  
 1st Qu.: 0.00000   1st Qu.:38.95   1st Qu.:-4.6800   1st Qu.:  42.0  
 Median : 0.00000   Median :40.84   Median :-2.0392   Median : 127.0  
 Mean   : 0.00364   Mean   :40.49   Mean   :-2.1999   Mean   : 303.5  
 3rd Qu.: 0.00000   3rd Qu.:41.98   3rd Qu.: 0.5706   3rd Qu.: 582.0  
 Max.   :35.00000   Max.   :43.57   Max.   : 4.2156   Max.   :1894.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

VisualizaciĂ³n de 5 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=5)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=5)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt           tmax          tmin            precip           nevada 
 Min.   : 1.000   Min.   : 13   Min.   :-33.00   Min.   :  0.00   Min.   :0  
 1st Qu.: 4.000   1st Qu.: 94   1st Qu.: 23.00   1st Qu.:  0.00   1st Qu.:0  
 Median : 7.000   Median :128   Median : 50.00   Median :  3.00   Median :0  
 Mean   : 6.603   Mean   :138   Mean   : 60.53   Mean   : 11.63   Mean   :0  
 3rd Qu.:10.000   3rd Qu.:183   3rd Qu.: 98.00   3rd Qu.: 14.00   3rd Qu.:0  
 Max.   :12.000   Max.   :253   Max.   :159.00   Max.   :309.00   Max.   :0  
   prof_nieve         longitud        latitud         altitud    
 Min.   : 0.0000   Min.   :28.31   Min.   :-16.5   Min.   :2371  
 1st Qu.: 0.0000   1st Qu.:28.31   1st Qu.:-16.5   1st Qu.:2371  
 Median : 0.0000   Median :28.31   Median :-16.5   Median :2371  
 Mean   : 0.1753   Mean   :28.31   Mean   :-16.5   Mean   :2371  
 3rd Qu.: 0.0000   3rd Qu.:28.31   3rd Qu.:-16.5   3rd Qu.:2371  
 Max.   :46.0000   Max.   :28.31   Max.   :-16.5   Max.   :2371  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt          tmax            tmin           precip            nevada 
 Min.   : 1.00   Min.   : 87.0   Min.   : 64.0   Min.   :  0.000   Min.   :0  
 1st Qu.: 3.00   1st Qu.:212.0   1st Qu.:150.0   1st Qu.:  0.000   1st Qu.:0  
 Median : 6.00   Median :233.0   Median :168.0   Median :  1.000   Median :0  
 Mean   : 6.49   Mean   :233.8   Mean   :169.3   Mean   :  6.536   Mean   :0  
 3rd Qu.: 9.00   3rd Qu.:259.0   3rd Qu.:196.0   3rd Qu.:  7.000   3rd Qu.:0  
 Max.   :12.00   Max.   :356.0   Max.   :244.0   Max.   :145.000   Max.   :0  
   prof_nieve           longitud        latitud          altitud     
 Min.   :0.0000000   Min.   :27.82   Min.   :-17.89   Min.   : 14.0  
 1st Qu.:0.0000000   1st Qu.:28.05   1st Qu.:-16.56   1st Qu.: 25.0  
 Median :0.0000000   Median :28.46   Median :-16.26   Median : 33.0  
 Mean   :0.0003511   Mean   :28.38   Mean   :-15.96   Mean   :131.9  
 3rd Qu.:0.0000000   3rd Qu.:28.48   3rd Qu.:-15.39   3rd Qu.: 64.0  
 Max.   :2.0000000   Max.   :28.95   Max.   :-13.60   Max.   :632.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt           tmax          tmin             precip      
 Min.   : 1.000   Min.   : -4   Min.   :-110.00   Min.   :  0.00  
 1st Qu.: 2.000   1st Qu.:129   1st Qu.:  33.00   1st Qu.:  5.00  
 Median : 4.000   Median :161   Median :  64.00   Median : 14.00  
 Mean   : 5.903   Mean   :160   Mean   :  62.34   Mean   : 19.45  
 3rd Qu.:11.000   3rd Qu.:190   3rd Qu.:  90.00   3rd Qu.: 26.00  
 Max.   :12.000   Max.   :306   Max.   : 207.00   Max.   :371.00  
     nevada           prof_nieve          longitud        latitud       
 Min.   :0.000000   Min.   : 0.00000   Min.   :35.28   Min.   :-8.6494  
 1st Qu.:0.000000   1st Qu.: 0.00000   1st Qu.:38.95   1st Qu.:-5.4981  
 Median :0.000000   Median : 0.00000   Median :40.96   Median :-2.9553  
 Mean   :0.000532   Mean   : 0.07726   Mean   :40.51   Mean   :-2.7233  
 3rd Qu.:0.000000   3rd Qu.: 0.00000   3rd Qu.:42.24   3rd Qu.: 0.3664  
 Max.   :6.000000   Max.   :75.00000   Max.   :43.57   Max.   : 4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.:  47.0  
 Median : 286.0  
 Mean   : 382.2  
 3rd Qu.: 667.0  
 Max.   :1405.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt           tmax             tmin             precip      
 Min.   : 1.000   Min.   :-53.00   Min.   :-121.00   Min.   :  0.00  
 1st Qu.: 4.000   1st Qu.: 32.00   1st Qu.: -30.00   1st Qu.: 16.00  
 Median : 7.000   Median : 80.00   Median :  13.00   Median : 29.00  
 Mean   : 6.548   Mean   : 87.82   Mean   :  16.78   Mean   : 33.94  
 3rd Qu.:10.000   3rd Qu.:141.00   3rd Qu.:  64.00   3rd Qu.: 46.00  
 Max.   :12.000   Max.   :257.00   Max.   : 147.00   Max.   :180.00  
     nevada    prof_nieve        longitud        latitud           altitud    
 Min.   :0   Min.   :   0.0   Min.   :40.78   Min.   :-4.0103   Min.   :1405  
 1st Qu.:0   1st Qu.:   0.0   1st Qu.:40.78   1st Qu.:-4.0103   1st Qu.:1894  
 Median :0   Median :   0.0   Median :42.38   Median : 0.8842   Median :2143  
 Mean   :0   Mean   :  13.5   Mean   :41.94   Mean   :-0.2252   Mean   :2089  
 3rd Qu.:0   3rd Qu.:   0.0   3rd Qu.:42.53   3rd Qu.: 1.5242   3rd Qu.:2316  
 Max.   :0   Max.   :1834.0   Max.   :42.77   Max.   : 2.4378   Max.   :2535  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt           tmax            tmin           precip           nevada 
 Min.   : 1.000   Min.   :164.0   Min.   : 54.0   Min.   :  0.00   Min.   :0  
 1st Qu.: 6.000   1st Qu.:241.0   1st Qu.:129.0   1st Qu.:  1.00   1st Qu.:0  
 Median : 7.000   Median :273.0   Median :153.0   Median :  6.00   Median :0  
 Mean   : 7.453   Mean   :272.1   Mean   :154.6   Mean   : 11.33   Mean   :0  
 3rd Qu.: 9.000   3rd Qu.:301.0   3rd Qu.:179.0   3rd Qu.: 15.00   3rd Qu.:0  
 Max.   :12.000   Max.   :403.0   Max.   :254.0   Max.   :422.00   Max.   :0  
   prof_nieve          longitud        latitud           altitud      
 Min.   : 0.00000   Min.   :35.28   Min.   :-8.6494   Min.   :   1.0  
 1st Qu.: 0.00000   1st Qu.:38.95   1st Qu.:-4.6800   1st Qu.:  42.0  
 Median : 0.00000   Median :40.84   Median :-2.0392   Median : 127.0  
 Mean   : 0.00364   Mean   :40.49   Mean   :-2.1999   Mean   : 303.5  
 3rd Qu.: 0.00000   3rd Qu.:41.98   3rd Qu.: 0.5706   3rd Qu.: 582.0  
 Max.   :35.00000   Max.   :43.57   Max.   : 4.2156   Max.   :1894.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

VisualizaciĂ³n de 6 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=6)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=6)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)
  df.cluster06 <- subset(df, cluster==6)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster06 <- select(df.cluster06, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt           tmax          tmin            precip           nevada 
 Min.   : 1.000   Min.   : 13   Min.   :-33.00   Min.   :  0.00   Min.   :0  
 1st Qu.: 4.000   1st Qu.: 94   1st Qu.: 23.00   1st Qu.:  0.00   1st Qu.:0  
 Median : 7.000   Median :128   Median : 50.00   Median :  3.00   Median :0  
 Mean   : 6.603   Mean   :138   Mean   : 60.53   Mean   : 11.63   Mean   :0  
 3rd Qu.:10.000   3rd Qu.:183   3rd Qu.: 98.00   3rd Qu.: 14.00   3rd Qu.:0  
 Max.   :12.000   Max.   :253   Max.   :159.00   Max.   :309.00   Max.   :0  
   prof_nieve         longitud        latitud         altitud    
 Min.   : 0.0000   Min.   :28.31   Min.   :-16.5   Min.   :2371  
 1st Qu.: 0.0000   1st Qu.:28.31   1st Qu.:-16.5   1st Qu.:2371  
 Median : 0.0000   Median :28.31   Median :-16.5   Median :2371  
 Mean   : 0.1753   Mean   :28.31   Mean   :-16.5   Mean   :2371  
 3rd Qu.: 0.0000   3rd Qu.:28.31   3rd Qu.:-16.5   3rd Qu.:2371  
 Max.   :46.0000   Max.   :28.31   Max.   :-16.5   Max.   :2371  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt          tmax            tmin           precip            nevada 
 Min.   : 1.00   Min.   : 87.0   Min.   : 64.0   Min.   :  0.000   Min.   :0  
 1st Qu.: 3.00   1st Qu.:212.0   1st Qu.:150.0   1st Qu.:  0.000   1st Qu.:0  
 Median : 6.00   Median :233.0   Median :168.0   Median :  1.000   Median :0  
 Mean   : 6.49   Mean   :233.8   Mean   :169.3   Mean   :  6.536   Mean   :0  
 3rd Qu.: 9.00   3rd Qu.:259.0   3rd Qu.:196.0   3rd Qu.:  7.000   3rd Qu.:0  
 Max.   :12.00   Max.   :356.0   Max.   :244.0   Max.   :145.000   Max.   :0  
   prof_nieve           longitud        latitud          altitud     
 Min.   :0.0000000   Min.   :27.82   Min.   :-17.89   Min.   : 14.0  
 1st Qu.:0.0000000   1st Qu.:28.05   1st Qu.:-16.56   1st Qu.: 25.0  
 Median :0.0000000   Median :28.46   Median :-16.26   Median : 33.0  
 Mean   :0.0003511   Mean   :28.38   Mean   :-15.96   Mean   :131.9  
 3rd Qu.:0.0000000   3rd Qu.:28.48   3rd Qu.:-15.39   3rd Qu.: 64.0  
 Max.   :2.0000000   Max.   :28.95   Max.   :-13.60   Max.   :632.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt           tmax          tmin             precip      
 Min.   : 1.000   Min.   : -4   Min.   :-110.00   Min.   :  0.00  
 1st Qu.: 2.000   1st Qu.: 94   1st Qu.:   1.00   1st Qu.:  5.00  
 Median : 3.000   Median :114   Median :  19.00   Median : 11.00  
 Mean   : 5.642   Mean   :115   Mean   :  17.06   Mean   : 14.42  
 3rd Qu.:11.000   3rd Qu.:137   3rd Qu.:  35.00   3rd Qu.: 20.00  
 Max.   :12.000   Max.   :203   Max.   :  86.00   Max.   :305.00  
     nevada           prof_nieve         longitud        latitud      
 Min.   :0.000000   Min.   : 0.0000   Min.   :37.13   Min.   :-6.600  
 1st Qu.:0.000000   1st Qu.: 0.0000   1st Qu.:40.47   1st Qu.:-4.115  
 Median :0.000000   Median : 0.0000   Median :41.11   Median :-3.450  
 Mean   :0.001837   Mean   : 0.1654   Mean   :41.09   Mean   :-2.594  
 3rd Qu.:0.000000   3rd Qu.: 0.0000   3rd Qu.:42.00   3rd Qu.:-1.411  
 Max.   :6.000000   Max.   :75.0000   Max.   :43.36   Max.   : 3.166  
    altitud      
 Min.   :   4.0  
 1st Qu.: 608.1  
 Median : 704.0  
 Mean   : 735.5  
 3rd Qu.: 900.0  
 Max.   :1405.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt           tmax            tmin            precip          nevada 
 Min.   : 1.000   Min.   : 60.0   Min.   :-31.00   Min.   :  0.0   Min.   :0  
 1st Qu.: 3.000   1st Qu.:154.0   1st Qu.: 59.00   1st Qu.:  6.0   1st Qu.:0  
 Median : 5.000   Median :176.0   Median : 79.00   Median : 15.0   Median :0  
 Mean   : 6.009   Mean   :178.3   Mean   : 80.82   Mean   : 21.5   Mean   :0  
 3rd Qu.:10.000   3rd Qu.:201.0   3rd Qu.: 99.00   3rd Qu.: 29.0   3rd Qu.:0  
 Max.   :12.000   Max.   :306.0   Max.   :207.00   Max.   :371.0   Max.   :0  
   prof_nieve          longitud        latitud           altitud      
 Min.   : 0.00000   Min.   :35.28   Min.   :-8.6494   Min.   :   1.0  
 1st Qu.: 0.00000   1st Qu.:37.96   1st Qu.:-5.6614   1st Qu.:  29.0  
 Median : 0.00000   Median :40.96   Median :-2.9553   Median :  91.0  
 Mean   : 0.04129   Mean   :40.27   Mean   :-2.7761   Mean   : 237.9  
 3rd Qu.: 0.00000   3rd Qu.:42.34   3rd Qu.: 0.4942   3rd Qu.: 412.0  
 Max.   :59.00000   Max.   :43.57   Max.   : 4.2156   Max.   :1405.0  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt           tmax             tmin             precip      
 Min.   : 1.000   Min.   :-53.00   Min.   :-121.00   Min.   :  0.00  
 1st Qu.: 4.000   1st Qu.: 32.00   1st Qu.: -30.00   1st Qu.: 16.00  
 Median : 7.000   Median : 80.00   Median :  13.00   Median : 29.00  
 Mean   : 6.548   Mean   : 87.82   Mean   :  16.78   Mean   : 33.94  
 3rd Qu.:10.000   3rd Qu.:141.00   3rd Qu.:  64.00   3rd Qu.: 46.00  
 Max.   :12.000   Max.   :257.00   Max.   : 147.00   Max.   :180.00  
     nevada    prof_nieve        longitud        latitud           altitud    
 Min.   :0   Min.   :   0.0   Min.   :40.78   Min.   :-4.0103   Min.   :1405  
 1st Qu.:0   1st Qu.:   0.0   1st Qu.:40.78   1st Qu.:-4.0103   1st Qu.:1894  
 Median :0   Median :   0.0   Median :42.38   Median : 0.8842   Median :2143  
 Mean   :0   Mean   :  13.5   Mean   :41.94   Mean   :-0.2252   Mean   :2089  
 3rd Qu.:0   3rd Qu.:   0.0   3rd Qu.:42.53   3rd Qu.: 1.5242   3rd Qu.:2316  
 Max.   :0   Max.   :1834.0   Max.   :42.77   Max.   : 2.4378   Max.   :2535  
if (!empty_nodes) summary(df.cluster06)
   fecha_cnt           tmax            tmin           precip           nevada 
 Min.   : 1.000   Min.   :164.0   Min.   : 54.0   Min.   :  0.00   Min.   :0  
 1st Qu.: 6.000   1st Qu.:241.0   1st Qu.:129.0   1st Qu.:  1.00   1st Qu.:0  
 Median : 7.000   Median :273.0   Median :153.0   Median :  6.00   Median :0  
 Mean   : 7.453   Mean   :272.1   Mean   :154.6   Mean   : 11.33   Mean   :0  
 3rd Qu.: 9.000   3rd Qu.:301.0   3rd Qu.:179.0   3rd Qu.: 15.00   3rd Qu.:0  
 Max.   :12.000   Max.   :403.0   Max.   :254.0   Max.   :422.00   Max.   :0  
   prof_nieve          longitud        latitud           altitud      
 Min.   : 0.00000   Min.   :35.28   Min.   :-8.6494   Min.   :   1.0  
 1st Qu.: 0.00000   1st Qu.:38.95   1st Qu.:-4.6800   1st Qu.:  42.0  
 Median : 0.00000   Median :40.84   Median :-2.0392   Median : 127.0  
 Mean   : 0.00364   Mean   :40.49   Mean   :-2.1999   Mean   : 303.5  
 3rd Qu.: 0.00000   3rd Qu.:41.98   3rd Qu.: 0.5706   3rd Qu.: 582.0  
 Max.   :35.00000   Max.   :43.57   Max.   : 4.2156   Max.   :1894.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1], dim(df.cluster06)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05", "cluster06"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.hist(df.cluster06)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster06)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
  df.cluster06.grouped <- mpr.group_by_geo(df.cluster06)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster06.grouped)

VisualizaciĂ³n de 8 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=8)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=8)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)
  df.cluster06 <- subset(df, cluster==6)
  df.cluster07 <- subset(df, cluster==7)
  df.cluster08 <- subset(df, cluster==8)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster06 <- select(df.cluster06, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster07 <- select(df.cluster07, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster08 <- select(df.cluster08, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt           tmax          tmin            precip           nevada 
 Min.   : 1.000   Min.   : 13   Min.   :-33.00   Min.   :  0.00   Min.   :0  
 1st Qu.: 4.000   1st Qu.: 94   1st Qu.: 23.00   1st Qu.:  0.00   1st Qu.:0  
 Median : 7.000   Median :128   Median : 50.00   Median :  3.00   Median :0  
 Mean   : 6.603   Mean   :138   Mean   : 60.53   Mean   : 11.63   Mean   :0  
 3rd Qu.:10.000   3rd Qu.:183   3rd Qu.: 98.00   3rd Qu.: 14.00   3rd Qu.:0  
 Max.   :12.000   Max.   :253   Max.   :159.00   Max.   :309.00   Max.   :0  
   prof_nieve         longitud        latitud         altitud    
 Min.   : 0.0000   Min.   :28.31   Min.   :-16.5   Min.   :2371  
 1st Qu.: 0.0000   1st Qu.:28.31   1st Qu.:-16.5   1st Qu.:2371  
 Median : 0.0000   Median :28.31   Median :-16.5   Median :2371  
 Mean   : 0.1753   Mean   :28.31   Mean   :-16.5   Mean   :2371  
 3rd Qu.: 0.0000   3rd Qu.:28.31   3rd Qu.:-16.5   3rd Qu.:2371  
 Max.   :46.0000   Max.   :28.31   Max.   :-16.5   Max.   :2371  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt          tmax            tmin           precip            nevada 
 Min.   : 1.00   Min.   : 87.0   Min.   : 64.0   Min.   :  0.000   Min.   :0  
 1st Qu.: 3.00   1st Qu.:212.0   1st Qu.:150.0   1st Qu.:  0.000   1st Qu.:0  
 Median : 6.00   Median :233.0   Median :168.0   Median :  1.000   Median :0  
 Mean   : 6.49   Mean   :233.8   Mean   :169.3   Mean   :  6.536   Mean   :0  
 3rd Qu.: 9.00   3rd Qu.:259.0   3rd Qu.:196.0   3rd Qu.:  7.000   3rd Qu.:0  
 Max.   :12.00   Max.   :356.0   Max.   :244.0   Max.   :145.000   Max.   :0  
   prof_nieve           longitud        latitud          altitud     
 Min.   :0.0000000   Min.   :27.82   Min.   :-17.89   Min.   : 14.0  
 1st Qu.:0.0000000   1st Qu.:28.05   1st Qu.:-16.56   1st Qu.: 25.0  
 Median :0.0000000   Median :28.46   Median :-16.26   Median : 33.0  
 Mean   :0.0003511   Mean   :28.38   Mean   :-15.96   Mean   :131.9  
 3rd Qu.:0.0000000   3rd Qu.:28.48   3rd Qu.:-15.39   3rd Qu.: 64.0  
 Max.   :2.0000000   Max.   :28.95   Max.   :-13.60   Max.   :632.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt           tmax          tmin             precip      
 Min.   : 1.000   Min.   : -4   Min.   :-110.00   Min.   :  0.00  
 1st Qu.: 2.000   1st Qu.: 94   1st Qu.:   1.00   1st Qu.:  5.00  
 Median : 3.000   Median :114   Median :  19.00   Median : 11.00  
 Mean   : 5.642   Mean   :115   Mean   :  17.06   Mean   : 14.42  
 3rd Qu.:11.000   3rd Qu.:137   3rd Qu.:  35.00   3rd Qu.: 20.00  
 Max.   :12.000   Max.   :203   Max.   :  86.00   Max.   :305.00  
     nevada           prof_nieve         longitud        latitud      
 Min.   :0.000000   Min.   : 0.0000   Min.   :37.13   Min.   :-6.600  
 1st Qu.:0.000000   1st Qu.: 0.0000   1st Qu.:40.47   1st Qu.:-4.115  
 Median :0.000000   Median : 0.0000   Median :41.11   Median :-3.450  
 Mean   :0.001837   Mean   : 0.1654   Mean   :41.09   Mean   :-2.594  
 3rd Qu.:0.000000   3rd Qu.: 0.0000   3rd Qu.:42.00   3rd Qu.:-1.411  
 Max.   :6.000000   Max.   :75.0000   Max.   :43.36   Max.   : 3.166  
    altitud      
 Min.   :   4.0  
 1st Qu.: 608.1  
 Median : 704.0  
 Mean   : 735.5  
 3rd Qu.: 900.0  
 Max.   :1405.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt           tmax            tmin            precip           nevada 
 Min.   : 1.000   Min.   : 92.0   Min.   :-31.00   Min.   :  0.00   Min.   :0  
 1st Qu.: 3.000   1st Qu.:162.0   1st Qu.: 57.00   1st Qu.:  4.00   1st Qu.:0  
 Median : 5.000   Median :182.0   Median : 75.00   Median : 11.00   Median :0  
 Mean   : 6.056   Mean   :182.7   Mean   : 73.84   Mean   : 14.99   Mean   :0  
 3rd Qu.:10.000   3rd Qu.:202.0   3rd Qu.: 91.00   3rd Qu.: 21.00   3rd Qu.:0  
 Max.   :12.000   Max.   :284.0   Max.   :159.00   Max.   :200.00   Max.   :0  
   prof_nieve          longitud        latitud           altitud      
 Min.   : 0.00000   Min.   :37.13   Min.   :-6.6000   Min.   :   1.0  
 1st Qu.: 0.00000   1st Qu.:39.49   1st Qu.:-1.8631   1st Qu.:  44.0  
 Median : 0.00000   Median :40.96   Median : 0.4914   Median : 196.0  
 Mean   : 0.03108   Mean   :40.58   Mean   :-0.2628   Mean   : 340.9  
 3rd Qu.: 0.00000   3rd Qu.:41.66   3rd Qu.: 1.6239   3rd Qu.: 611.0  
 Max.   :59.00000   Max.   :42.87   Max.   : 4.2156   Max.   :1405.0  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt           tmax             tmin             precip      
 Min.   : 1.000   Min.   :-53.00   Min.   :-121.00   Min.   :  0.00  
 1st Qu.: 4.000   1st Qu.: 32.00   1st Qu.: -30.00   1st Qu.: 16.00  
 Median : 7.000   Median : 80.00   Median :  13.00   Median : 29.00  
 Mean   : 6.548   Mean   : 87.82   Mean   :  16.78   Mean   : 33.94  
 3rd Qu.:10.000   3rd Qu.:141.00   3rd Qu.:  64.00   3rd Qu.: 46.00  
 Max.   :12.000   Max.   :257.00   Max.   : 147.00   Max.   :180.00  
     nevada    prof_nieve        longitud        latitud           altitud    
 Min.   :0   Min.   :   0.0   Min.   :40.78   Min.   :-4.0103   Min.   :1405  
 1st Qu.:0   1st Qu.:   0.0   1st Qu.:40.78   1st Qu.:-4.0103   1st Qu.:1894  
 Median :0   Median :   0.0   Median :42.38   Median : 0.8842   Median :2143  
 Mean   :0   Mean   :  13.5   Mean   :41.94   Mean   :-0.2252   Mean   :2089  
 3rd Qu.:0   3rd Qu.:   0.0   3rd Qu.:42.53   3rd Qu.: 1.5242   3rd Qu.:2316  
 Max.   :0   Max.   :1834.0   Max.   :42.77   Max.   : 2.4378   Max.   :2535  
if (!empty_nodes) summary(df.cluster06)
   fecha_cnt           tmax          tmin         precip           nevada 
 Min.   : 1.000   Min.   : 95   Min.   :-10   Min.   :  0.00   Min.   :0  
 1st Qu.: 3.000   1st Qu.:170   1st Qu.: 82   1st Qu.:  4.00   1st Qu.:0  
 Median : 5.000   Median :195   Median :108   Median : 12.00   Median :0  
 Mean   : 6.091   Mean   :200   Mean   :108   Mean   : 18.02   Mean   :0  
 3rd Qu.:10.000   3rd Qu.:228   3rd Qu.:134   3rd Qu.: 25.00   3rd Qu.:0  
 Max.   :12.000   Max.   :306   Max.   :207   Max.   :259.00   Max.   :0  
   prof_nieve          longitud        latitud          altitud   
 Min.   : 0.00000   Min.   :35.28   Min.   :-6.949   Min.   :  1  
 1st Qu.: 0.00000   1st Qu.:36.50   1st Qu.:-6.257   1st Qu.: 19  
 Median : 0.00000   Median :36.75   Median :-5.600   Median : 32  
 Mean   : 0.01885   Mean   :36.82   Mean   :-5.382   Mean   : 61  
 3rd Qu.: 0.00000   3rd Qu.:37.26   3rd Qu.:-4.846   3rd Qu.: 87  
 Max.   :34.00000   Max.   :39.47   Max.   :-2.357   Max.   :582  
if (!empty_nodes) summary(df.cluster07)
   fecha_cnt           tmax            tmin            precip           nevada 
 Min.   : 1.000   Min.   : 60.0   Min.   :-28.00   Min.   :  0.00   Min.   :0  
 1st Qu.: 2.000   1st Qu.:129.0   1st Qu.: 53.00   1st Qu.: 18.00   1st Qu.:0  
 Median : 4.000   Median :147.0   Median : 70.00   Median : 32.00   Median :0  
 Mean   : 5.827   Mean   :147.7   Mean   : 69.41   Mean   : 38.92   Mean   :0  
 3rd Qu.:11.000   3rd Qu.:166.0   3rd Qu.: 87.00   3rd Qu.: 52.00   3rd Qu.:0  
 Max.   :12.000   Max.   :254.0   Max.   :140.00   Max.   :371.00   Max.   :0  
   prof_nieve          longitud        latitud          altitud     
 Min.   : 0.00000   Min.   :38.88   Min.   :-8.649   Min.   :  4.0  
 1st Qu.: 0.00000   1st Qu.:42.56   1st Qu.:-8.411   1st Qu.: 52.0  
 Median : 0.00000   Median :43.31   Median :-6.044   Median :127.0  
 Mean   : 0.08521   Mean   :42.98   Mean   :-5.660   Mean   :188.2  
 3rd Qu.: 0.00000   3rd Qu.:43.43   3rd Qu.:-3.799   3rd Qu.:336.0  
 Max.   :40.00000   Max.   :43.57   Max.   :-1.008   Max.   :534.0  
if (!empty_nodes) summary(df.cluster08)
   fecha_cnt           tmax            tmin           precip           nevada 
 Min.   : 1.000   Min.   :164.0   Min.   : 54.0   Min.   :  0.00   Min.   :0  
 1st Qu.: 6.000   1st Qu.:241.0   1st Qu.:129.0   1st Qu.:  1.00   1st Qu.:0  
 Median : 7.000   Median :273.0   Median :153.0   Median :  6.00   Median :0  
 Mean   : 7.453   Mean   :272.1   Mean   :154.6   Mean   : 11.33   Mean   :0  
 3rd Qu.: 9.000   3rd Qu.:301.0   3rd Qu.:179.0   3rd Qu.: 15.00   3rd Qu.:0  
 Max.   :12.000   Max.   :403.0   Max.   :254.0   Max.   :422.00   Max.   :0  
   prof_nieve          longitud        latitud           altitud      
 Min.   : 0.00000   Min.   :35.28   Min.   :-8.6494   Min.   :   1.0  
 1st Qu.: 0.00000   1st Qu.:38.95   1st Qu.:-4.6800   1st Qu.:  42.0  
 Median : 0.00000   Median :40.84   Median :-2.0392   Median : 127.0  
 Mean   : 0.00364   Mean   :40.49   Mean   :-2.1999   Mean   : 303.5  
 3rd Qu.: 0.00000   3rd Qu.:41.98   3rd Qu.: 0.5706   3rd Qu.: 582.0  
 Max.   :35.00000   Max.   :43.57   Max.   : 4.2156   Max.   :1894.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1], dim(df.cluster06)[1], dim(df.cluster07)[1], dim(df.cluster08)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05", "cluster06", "cluster07", "cluster08"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.hist(df.cluster06)

if (!empty_nodes) mpr.hist(df.cluster07)

if (!empty_nodes) mpr.hist(df.cluster08)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster06)

if (!empty_nodes) mpr.boxplot(df.cluster07)

if (!empty_nodes) mpr.boxplot(df.cluster08)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
  df.cluster06.grouped <- mpr.group_by_geo(df.cluster06)
  df.cluster07.grouped <- mpr.group_by_geo(df.cluster07)
  df.cluster08.grouped <- mpr.group_by_geo(df.cluster08)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster06.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster07.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster08.grouped)

VisualizaciĂ³n de 10 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=10)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=10)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)
  df.cluster06 <- subset(df, cluster==6)
  df.cluster07 <- subset(df, cluster==7)
  df.cluster08 <- subset(df, cluster==8)
  df.cluster09 <- subset(df, cluster==9)
  df.cluster10 <- subset(df, cluster==10)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster06 <- select(df.cluster06, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster07 <- select(df.cluster07, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster08 <- select(df.cluster08, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster09 <- select(df.cluster09, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster10 <- select(df.cluster10, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt           tmax          tmin            precip           nevada 
 Min.   : 1.000   Min.   : 13   Min.   :-33.00   Min.   :  0.00   Min.   :0  
 1st Qu.: 4.000   1st Qu.: 94   1st Qu.: 23.00   1st Qu.:  0.00   1st Qu.:0  
 Median : 7.000   Median :128   Median : 50.00   Median :  3.00   Median :0  
 Mean   : 6.603   Mean   :138   Mean   : 60.53   Mean   : 11.63   Mean   :0  
 3rd Qu.:10.000   3rd Qu.:183   3rd Qu.: 98.00   3rd Qu.: 14.00   3rd Qu.:0  
 Max.   :12.000   Max.   :253   Max.   :159.00   Max.   :309.00   Max.   :0  
   prof_nieve         longitud        latitud         altitud    
 Min.   : 0.0000   Min.   :28.31   Min.   :-16.5   Min.   :2371  
 1st Qu.: 0.0000   1st Qu.:28.31   1st Qu.:-16.5   1st Qu.:2371  
 Median : 0.0000   Median :28.31   Median :-16.5   Median :2371  
 Mean   : 0.1753   Mean   :28.31   Mean   :-16.5   Mean   :2371  
 3rd Qu.: 0.0000   3rd Qu.:28.31   3rd Qu.:-16.5   3rd Qu.:2371  
 Max.   :46.0000   Max.   :28.31   Max.   :-16.5   Max.   :2371  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt          tmax            tmin           precip            nevada 
 Min.   : 1.00   Min.   : 87.0   Min.   : 64.0   Min.   :  0.000   Min.   :0  
 1st Qu.: 3.00   1st Qu.:212.0   1st Qu.:150.0   1st Qu.:  0.000   1st Qu.:0  
 Median : 6.00   Median :233.0   Median :168.0   Median :  1.000   Median :0  
 Mean   : 6.49   Mean   :233.8   Mean   :169.3   Mean   :  6.536   Mean   :0  
 3rd Qu.: 9.00   3rd Qu.:259.0   3rd Qu.:196.0   3rd Qu.:  7.000   3rd Qu.:0  
 Max.   :12.00   Max.   :356.0   Max.   :244.0   Max.   :145.000   Max.   :0  
   prof_nieve           longitud        latitud          altitud     
 Min.   :0.0000000   Min.   :27.82   Min.   :-17.89   Min.   : 14.0  
 1st Qu.:0.0000000   1st Qu.:28.05   1st Qu.:-16.56   1st Qu.: 25.0  
 Median :0.0000000   Median :28.46   Median :-16.26   Median : 33.0  
 Mean   :0.0003511   Mean   :28.38   Mean   :-15.96   Mean   :131.9  
 3rd Qu.:0.0000000   3rd Qu.:28.48   3rd Qu.:-15.39   3rd Qu.: 64.0  
 Max.   :2.0000000   Max.   :28.95   Max.   :-13.60   Max.   :632.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt           tmax          tmin             precip      
 Min.   : 1.000   Min.   : -4   Min.   :-110.00   Min.   :  0.00  
 1st Qu.: 2.000   1st Qu.: 94   1st Qu.:   1.00   1st Qu.:  5.00  
 Median : 3.000   Median :114   Median :  19.00   Median : 11.00  
 Mean   : 5.642   Mean   :115   Mean   :  17.06   Mean   : 14.42  
 3rd Qu.:11.000   3rd Qu.:137   3rd Qu.:  35.00   3rd Qu.: 20.00  
 Max.   :12.000   Max.   :203   Max.   :  86.00   Max.   :305.00  
     nevada           prof_nieve         longitud        latitud      
 Min.   :0.000000   Min.   : 0.0000   Min.   :37.13   Min.   :-6.600  
 1st Qu.:0.000000   1st Qu.: 0.0000   1st Qu.:40.47   1st Qu.:-4.115  
 Median :0.000000   Median : 0.0000   Median :41.11   Median :-3.450  
 Mean   :0.001837   Mean   : 0.1654   Mean   :41.09   Mean   :-2.594  
 3rd Qu.:0.000000   3rd Qu.: 0.0000   3rd Qu.:42.00   3rd Qu.:-1.411  
 Max.   :6.000000   Max.   :75.0000   Max.   :43.36   Max.   : 3.166  
    altitud      
 Min.   :   4.0  
 1st Qu.: 608.1  
 Median : 704.0  
 Mean   : 735.5  
 3rd Qu.: 900.0  
 Max.   :1405.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt           tmax            tmin            precip           nevada 
 Min.   : 1.000   Min.   : 92.0   Min.   :-31.00   Min.   :  0.00   Min.   :0  
 1st Qu.: 3.000   1st Qu.:162.0   1st Qu.: 57.00   1st Qu.:  4.00   1st Qu.:0  
 Median : 5.000   Median :182.0   Median : 75.00   Median : 11.00   Median :0  
 Mean   : 6.056   Mean   :182.7   Mean   : 73.84   Mean   : 14.99   Mean   :0  
 3rd Qu.:10.000   3rd Qu.:202.0   3rd Qu.: 91.00   3rd Qu.: 21.00   3rd Qu.:0  
 Max.   :12.000   Max.   :284.0   Max.   :159.00   Max.   :200.00   Max.   :0  
   prof_nieve          longitud        latitud           altitud      
 Min.   : 0.00000   Min.   :37.13   Min.   :-6.6000   Min.   :   1.0  
 1st Qu.: 0.00000   1st Qu.:39.49   1st Qu.:-1.8631   1st Qu.:  44.0  
 Median : 0.00000   Median :40.96   Median : 0.4914   Median : 196.0  
 Mean   : 0.03108   Mean   :40.58   Mean   :-0.2628   Mean   : 340.9  
 3rd Qu.: 0.00000   3rd Qu.:41.66   3rd Qu.: 1.6239   3rd Qu.: 611.0  
 Max.   :59.00000   Max.   :42.87   Max.   : 4.2156   Max.   :1405.0  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt           tmax             tmin             precip      
 Min.   : 1.000   Min.   :-53.00   Min.   :-121.00   Min.   :  0.00  
 1st Qu.: 4.000   1st Qu.: 32.00   1st Qu.: -30.00   1st Qu.: 16.00  
 Median : 7.000   Median : 80.00   Median :  13.00   Median : 29.00  
 Mean   : 6.548   Mean   : 87.82   Mean   :  16.78   Mean   : 33.94  
 3rd Qu.:10.000   3rd Qu.:141.00   3rd Qu.:  64.00   3rd Qu.: 46.00  
 Max.   :12.000   Max.   :257.00   Max.   : 147.00   Max.   :180.00  
     nevada    prof_nieve        longitud        latitud           altitud    
 Min.   :0   Min.   :   0.0   Min.   :40.78   Min.   :-4.0103   Min.   :1405  
 1st Qu.:0   1st Qu.:   0.0   1st Qu.:40.78   1st Qu.:-4.0103   1st Qu.:1894  
 Median :0   Median :   0.0   Median :42.38   Median : 0.8842   Median :2143  
 Mean   :0   Mean   :  13.5   Mean   :41.94   Mean   :-0.2252   Mean   :2089  
 3rd Qu.:0   3rd Qu.:   0.0   3rd Qu.:42.53   3rd Qu.: 1.5242   3rd Qu.:2316  
 Max.   :0   Max.   :1834.0   Max.   :42.77   Max.   : 2.4378   Max.   :2535  
if (!empty_nodes) summary(df.cluster06)
   fecha_cnt           tmax          tmin         precip           nevada 
 Min.   : 1.000   Min.   : 95   Min.   :-10   Min.   :  0.00   Min.   :0  
 1st Qu.: 3.000   1st Qu.:170   1st Qu.: 82   1st Qu.:  4.00   1st Qu.:0  
 Median : 5.000   Median :195   Median :108   Median : 12.00   Median :0  
 Mean   : 6.091   Mean   :200   Mean   :108   Mean   : 18.02   Mean   :0  
 3rd Qu.:10.000   3rd Qu.:228   3rd Qu.:134   3rd Qu.: 25.00   3rd Qu.:0  
 Max.   :12.000   Max.   :306   Max.   :207   Max.   :259.00   Max.   :0  
   prof_nieve          longitud        latitud          altitud   
 Min.   : 0.00000   Min.   :35.28   Min.   :-6.949   Min.   :  1  
 1st Qu.: 0.00000   1st Qu.:36.50   1st Qu.:-6.257   1st Qu.: 19  
 Median : 0.00000   Median :36.75   Median :-5.600   Median : 32  
 Mean   : 0.01885   Mean   :36.82   Mean   :-5.382   Mean   : 61  
 3rd Qu.: 0.00000   3rd Qu.:37.26   3rd Qu.:-4.846   3rd Qu.: 87  
 Max.   :34.00000   Max.   :39.47   Max.   :-2.357   Max.   :582  
if (!empty_nodes) summary(df.cluster07)
   fecha_cnt           tmax            tmin            precip           nevada 
 Min.   : 1.000   Min.   : 60.0   Min.   :-28.00   Min.   :  0.00   Min.   :0  
 1st Qu.: 2.000   1st Qu.:129.0   1st Qu.: 53.00   1st Qu.: 18.00   1st Qu.:0  
 Median : 4.000   Median :147.0   Median : 70.00   Median : 32.00   Median :0  
 Mean   : 5.827   Mean   :147.7   Mean   : 69.41   Mean   : 38.92   Mean   :0  
 3rd Qu.:11.000   3rd Qu.:166.0   3rd Qu.: 87.00   3rd Qu.: 52.00   3rd Qu.:0  
 Max.   :12.000   Max.   :254.0   Max.   :140.00   Max.   :371.00   Max.   :0  
   prof_nieve          longitud        latitud          altitud     
 Min.   : 0.00000   Min.   :38.88   Min.   :-8.649   Min.   :  4.0  
 1st Qu.: 0.00000   1st Qu.:42.56   1st Qu.:-8.411   1st Qu.: 52.0  
 Median : 0.00000   Median :43.31   Median :-6.044   Median :127.0  
 Mean   : 0.08521   Mean   :42.98   Mean   :-5.660   Mean   :188.2  
 3rd Qu.: 0.00000   3rd Qu.:43.43   3rd Qu.:-3.799   3rd Qu.:336.0  
 Max.   :40.00000   Max.   :43.57   Max.   :-1.008   Max.   :534.0  
if (!empty_nodes) summary(df.cluster08)
   fecha_cnt           tmax            tmin           precip            nevada 
 Min.   : 4.000   Min.   :198.0   Min.   : 54.0   Min.   :  0.000   Min.   :0  
 1st Qu.: 6.000   1st Qu.:258.0   1st Qu.:114.0   1st Qu.:  1.000   1st Qu.:0  
 Median : 7.000   Median :283.0   Median :134.0   Median :  5.000   Median :0  
 Mean   : 7.375   Mean   :285.2   Mean   :137.2   Mean   :  7.248   Mean   :0  
 3rd Qu.: 8.000   3rd Qu.:311.0   3rd Qu.:158.0   3rd Qu.: 11.000   3rd Qu.:0  
 Max.   :10.000   Max.   :400.0   Max.   :250.0   Max.   :150.000   Max.   :0  
   prof_nieve         longitud        latitud          altitud      
 Min.   : 0.0000   Min.   :37.13   Min.   :-6.600   Min.   : 353.0  
 1st Qu.: 0.0000   1st Qu.:39.88   1st Qu.:-4.127   1st Qu.: 617.0  
 Median : 0.0000   Median :40.48   Median :-3.788   Median : 687.0  
 Mean   : 0.0039   Mean   :40.46   Mean   :-3.597   Mean   : 745.7  
 3rd Qu.: 0.0000   3rd Qu.:41.11   3rd Qu.:-2.654   3rd Qu.: 890.0  
 Max.   :35.0000   Max.   :42.87   Max.   : 2.414   Max.   :1894.0  
if (!empty_nodes) summary(df.cluster09)
   fecha_cnt           tmax            tmin           precip           nevada 
 Min.   : 1.000   Min.   :183.0   Min.   : 81.0   Min.   :  0.00   Min.   :0  
 1st Qu.: 6.000   1st Qu.:254.0   1st Qu.:145.0   1st Qu.:  1.00   1st Qu.:0  
 Median : 7.000   Median :281.0   Median :171.0   Median :  5.00   Median :0  
 Mean   : 7.454   Mean   :279.5   Mean   :168.9   Mean   : 10.05   Mean   :0  
 3rd Qu.: 9.000   3rd Qu.:305.0   3rd Qu.:193.0   3rd Qu.: 14.00   3rd Qu.:0  
 Max.   :12.000   Max.   :403.0   Max.   :254.0   Max.   :320.00   Max.   :0  
   prof_nieve           longitud        latitud           altitud      
 Min.   : 0.000000   Min.   :35.28   Min.   :-6.9492   Min.   :   1.0  
 1st Qu.: 0.000000   1st Qu.:37.98   1st Qu.:-1.2294   1st Qu.:  17.0  
 Median : 0.000000   Median :39.85   Median : 0.4914   Median :  61.0  
 Mean   : 0.001992   Mean   :39.66   Mean   :-0.4013   Mean   : 118.7  
 3rd Qu.: 0.000000   3rd Qu.:41.43   3rd Qu.: 1.3842   3rd Qu.: 147.0  
 Max.   :27.000000   Max.   :43.36   Max.   : 4.2156   Max.   :1167.0  
if (!empty_nodes) summary(df.cluster10)
   fecha_cnt           tmax            tmin           precip           nevada 
 Min.   : 2.000   Min.   :164.0   Min.   : 64.0   Min.   :  0.00   Min.   :0  
 1st Qu.: 6.000   1st Qu.:210.0   1st Qu.:124.0   1st Qu.:  8.00   1st Qu.:0  
 Median : 8.000   Median :225.0   Median :139.0   Median : 17.00   Median :0  
 Mean   : 7.574   Mean   :227.4   Mean   :138.3   Mean   : 21.98   Mean   :0  
 3rd Qu.: 9.000   3rd Qu.:242.0   3rd Qu.:153.0   3rd Qu.: 29.00   3rd Qu.:0  
 Max.   :12.000   Max.   :340.0   Max.   :219.0   Max.   :422.00   Max.   :0  
   prof_nieve           longitud        latitud          altitud     
 Min.   : 0.000000   Min.   :39.47   Min.   :-8.649   Min.   :  4.0  
 1st Qu.: 0.000000   1st Qu.:42.89   1st Qu.:-8.372   1st Qu.: 42.0  
 Median : 0.000000   Median :43.31   Median :-5.698   Median : 64.0  
 Mean   : 0.008316   Mean   :43.08   Mean   :-5.512   Mean   :156.8  
 3rd Qu.: 0.000000   3rd Qu.:43.46   3rd Qu.:-3.799   3rd Qu.:261.0  
 Max.   :27.000000   Max.   :43.57   Max.   :-1.636   Max.   :534.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1], dim(df.cluster06)[1], dim(df.cluster07)[1], dim(df.cluster08)[1], dim(df.cluster09)[1], dim(df.cluster10)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05", "cluster06", "cluster07", "cluster08", "cluster09", "cluster10"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.hist(df.cluster06)

if (!empty_nodes) mpr.hist(df.cluster07)

if (!empty_nodes) mpr.hist(df.cluster08)

if (!empty_nodes) mpr.hist(df.cluster09)

if (!empty_nodes) mpr.hist(df.cluster10)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster06)

if (!empty_nodes) mpr.boxplot(df.cluster07)

if (!empty_nodes) mpr.boxplot(df.cluster08)

if (!empty_nodes) mpr.boxplot(df.cluster09)

if (!empty_nodes) mpr.boxplot(df.cluster10)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
  df.cluster06.grouped <- mpr.group_by_geo(df.cluster06)
  df.cluster07.grouped <- mpr.group_by_geo(df.cluster07)
  df.cluster08.grouped <- mpr.group_by_geo(df.cluster08)
  df.cluster09.grouped <- mpr.group_by_geo(df.cluster09)
  df.cluster10.grouped <- mpr.group_by_geo(df.cluster10)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster06.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster07.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster08.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster09.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster10.grouped)

LS0tCnRpdGxlOiAiQW7DoWxpc2lzIGRlIG1vZGVsb3MgU09NIC0gRnJlY3VlbmNpYSBkYXRvcyBkZSBlbnRyYWRhOiBtZXMiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMgTW9kZWxvCgoqIElEOiAzMDUKKiBEZXNjcmlwY2nDs246IAoqIEZyZWN1ZW5jaWE6IG1lcwoqIFZhcmlhYmxlczogdG1heCwgdG1pbiwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQKKiBEaW1lbnNpb25lcyBkZWwgbWFwYTogNSw1CiogSXRlcmFjaW9uZXM6IDEwMDAKKiBQYXLDoW1ldHJvcyBhZGljaW9uYWxlczogCgpgYGB7cn0Kc291cmNlKCIuLi8uLi9saWIvc29tLXV0aWxzLlIiKQpzb3VyY2UoIi4uLy4uL2xpYi9tYXBzLXV0aWxzLlIiKQpgYGAKCiMgQ2FyZ2EgZGVsIG1vZGVsbyBkZXNkZSBkaXNjbwoKYGBge3J9Cm1wci5zZXRfYmFzZV9wYXRoX2FuYWx5c2lzKCkKbW9kZWwgPC0gbXByLmxvYWRfbW9kZWwoInNvbS0zMDUucmRzLnh6IikKc3VtbWFyeShtb2RlbCkKYGBgCgpgYGB7cn0KcGxvdChtb2RlbCwgdHlwZT0iY2hhbmdlcyIpCmBgYAoKIyBDYXJnYSBkZWwgZGF0YXNldCBkZSBlbnRyYWRhCgpgYGB7cn0KZGYgPC0gbXByLmxvYWRfZGF0YSgiZGF0b3NfbWVzLmNzdi54eiIpCmBgYAoKYGBge3J9CmRmCmBgYAoKYGBge3J9CnN1bW1hcnkoZGYpCmBgYAoKIyBDYXJnYSBkZSBsb3MgbWFwYXMKCmBgYHtyfQp3b3JsZCA8LSBuZV9jb3VudHJpZXMoc2NhbGUgPSAibWVkaXVtIiwgcmV0dXJuY2xhc3MgPSAic2YiKQpzcGFpbiA8LSBzdWJzZXQod29ybGQsIGFkbWluID09ICJTcGFpbiIpCmBgYAoKIyBNYXBhIGRlIGRlbnNpZGFkCgpgYGB7cn0KcGxvdChtb2RlbCwgdHlwZT0iY291bnQiLCBzaGFwZSA9ICJzdHJhaWdodCIsIHBhbGV0dGUubmFtZSA9IG1wci5kZWdyYWRlLmJsZXUpCmBgYAoKTsO6bWVybyBkZSBlbGVtZW50b3MgZW4gY2FkYSBjZWxkYToKCmBgYHtyfQpuYiA8LSB0YWJsZShtb2RlbCR1bml0LmNsYXNzaWYpCnByaW50KG5iKQpgYGAKQ29tcHJvYmFjacOzbiBkZSBub2RvcyB2YWPDrW9zOgoKYGBge3J9CmRpbV9tb2RlbCA8LSA1KjU7Cmxlbl9uYiA9IGxlbmd0aChuYik7CmVtcHR5X25vZGVzIDwtIGRpbV9tb2RlbCAhPSBsZW5fbmI7CmlmIChlbXB0eV9ub2RlcykgewogIHByaW50KHBhc3RlKCJbV2FybmluZ10gRXhpc3RlbiBub2RvcyB2YWPDrW9zOiAiLCBsZW5fbmIsICIvIiwgZGltX21vZGVsKSkKfQpgYGAKCiMgTWFwYSBkZSBkaXN0YW5jaWEgZW50cmUgdmVjaW5vcwoKYGBge3J9CnBsb3QobW9kZWwsIHR5cGU9ImRpc3QubmVpZ2hib3VycyIsIHNoYXBlID0gInN0cmFpZ2h0IikKYGBgCgojIEluZmx1ZW5jaWEgZGUgbGFzIHZhcmlhYmxlcwoKYGBge3J9Cm1vZGVsX2NvbG5hbWVzID0gYygidG1heCIsICJ0bWluIiwgImxvbmdpdHVkIiwgImxhdGl0dWQiLCAiYWx0aXR1ZCIpCm1vZGVsX25jb2wgPSBsZW5ndGgobW9kZWxfY29sbmFtZXMpCmBgYAoKIyMgTWFwYSBkZSB2YXJpYWJsZXMuCgpgYGB7cn0KcGxvdChtb2RlbCwgc2hhcGUgPSAic3RyYWlnaHQiKQpgYGAKCiMjIE1hcGEgZGUgY2Fsb3IgcG9yIHZhcmlhYmxlCgpgYGB7cn0KcGFyKG1mcm93PWMoMyw0KSkKZm9yIChqIGluIDE6bW9kZWxfbmNvbCkgewogIHBsb3QobW9kZWwsIHR5cGU9InByb3BlcnR5IiwgcHJvcGVydHk9Z2V0Q29kZXMobW9kZWwsMSlbLGpdLAogICAgcGFsZXR0ZS5uYW1lPW1wci5jb29sQmx1ZUhvdFJlZCwKICAgIG1haW49bW9kZWxfY29sbmFtZXNbal0sCiAgICBjZXg9MC41LCBzaGFwZSA9ICJzdHJhaWdodCIpCn0KYGBgCgojIyBDb3JyZWxhY2nDs24gcGFyYSBjYWRhIGNvbHVtbmEgZGVsIHZlY3RvciBkZSBub2RvcwoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBjb3IgPC0gYXBwbHkoZ2V0Q29kZXMobW9kZWwsMSksIDIsIG1wci53ZWlnaHRlZC5jb3JyZWxhdGlvbiwgdz1uYiwgc29tPW1vZGVsKQogIHByaW50KGNvcikKfQpgYGAKClJlcHJlc2VudGFjacOzbiBkZSBjYWRhIHZhcmlhYmxlIGVuIHVuIG1hcGEgZGUgZmFjdG9yZXM6CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIHBhcihtZnJvdz1jKDEsMSkpCiAgcGxvdChjb3JbMSxdLCBjb3JbMixdLCB4bGltPWMoLTEsMSksIHlsaW09YygtMSwxKSwgdHlwZT0ibiIpCiAgbGluZXMoYygtMSwxKSxjKDAsMCkpCiAgbGluZXMoYygwLDApLGMoLTEsMSkpCiAgdGV4dChjb3JbMSxdLCBjb3JbMixdLCBsYWJlbHM9bW9kZWxfY29sbmFtZXMsIGNleD0wLjc1KQogIHN5bWJvbHMoMCwwLGNpcmNsZXM9MSxpbmNoZXM9RixhZGQ9VCkKfQpgYGAKCkltcG9ydGFuY2lhIGRlIGNhZGEgdmFyaWFibGUgLSB2YXJpYW56YSBwb25kZXJhZGEgcG9yIGVsIHRhbWHDsW8gZGUgbGEgY2VsZGE6CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIHNpZ21hMiA8LSBzcXJ0KGFwcGx5KGdldENvZGVzKG1vZGVsLDEpLDIsZnVuY3Rpb24oeCxlZmZlY3RpZikKICAgICB7bTwtc3VtKGVmZmVjdGlmKih4LXdlaWdodGVkLm1lYW4oeCxlZmZlY3RpZikpXjIpLyhzdW0oZWZmZWN0aWYpLTEpfSwKICAgICBlZmZlY3RpZj1uYikpCiAgcHJpbnQoc29ydChzaWdtYTIsZGVjcmVhc2luZz1UKSkKfQpgYGAKCiMgQ2x1c3RlcmluZwoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBoYWMgPC0gbXByLmhhYyhtb2RlbCwgbmIpCn0KYGBgCgojIyBWaXN1YWxpemFjacOzbiBkZSAzIGNsw7pzdGVyZXM6CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIHBsb3QoaGFjLCBoYW5nPS0xLCBsYWJlbHM9RikKICByZWN0LmhjbHVzdChoYWMsIGs9MykKfQpgYGAKCiMjIyBWaXN1YWxpemFjacOzbiBkZSBsb3MgY2zDunN0ZXJzIGVuIGVsIG1hcGEKCkEgcXXDqSBjbMO6c3RlciBwZXJ0ZW5lY2UgY2FkYSBub2RvIGRlbCBtYXBhIGRlIGtvaG9uZW46CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGdyb3VwcyA8LSBjdXRyZWUoaGFjLCBrPTMpCiAgcGxvdChtb2RlbCwgdHlwZT0ibWFwcGluZyIsCiAgICBiZ2NvbD1jKCJzdGVlbGJsdWUxIiwic2llbm5hMSIsInllbGxvd2dyZWVuIiwicmVkIiwiYmx1ZSIsInllbGxvdyIsInB1cnBsZSIsImdyZWVuIiwid2hpdGUiLCIjMWY3N2I0IiwgJyNmZjdmMGUnLCAnIzJjYTAyYycsICcjZDYyNzI4JywgJyM5NDY3YmQnLCAnIzhjNTY0YicsICcjZTM3N2MyJylbZ3JvdXBzXSwKICAgIHNoYXBlID0gInN0cmFpZ2h0IiwgbGFiZWxzID0gIiIpCiAgYWRkLmNsdXN0ZXIuYm91bmRhcmllcyhtb2RlbCwgY2x1c3RlcmluZz1ncm91cHMpCn0KYGBgCgojIyMgQW7DoWxpc2lzIGRlIGxhcyBvYnNlcnZhY2lvbmVzIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICAjIEFzaWduYW1vcyBhIGNhZGEgcmVnaXN0cm8gc3UgY2zDunN0ZXIKICBkZiRjbHVzdGVyIDwtIGdyb3Vwc1ttb2RlbCR1bml0LmNsYXNzaWZdCn0KYGBgCgpOdWV2b3MgZGF0YWZyYW1lcyBwb3IgY2x1c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICAjIENyZW8gbnVldm9zIGRhdGFmcmFtZXMsIHVubyBwb3IgY2FkYSBjbMO6c3Rlci4KICBkZi5jbHVzdGVyMDEgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0xKQogIGRmLmNsdXN0ZXIwMiA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTIpCiAgZGYuY2x1c3RlcjAzIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MykKCiAgIyBFeHRyYWlnbyBkZWwgZGF0YWZyYW1lIGxhcyBmZWF0dXJlcy4KICBkZi5jbHVzdGVyMDEgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAyIDwtIHNlbGVjdChkZi5jbHVzdGVyMDIsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMyA8LSBzZWxlY3QoZGYuY2x1c3RlcjAzLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAzKQpgYGAKCiMjIyMgTsO6bWVybyBkZSBlbGVtZW50b3MgZW4gY2FkYSBjbMO6c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVycy5kaW0gPC0gYyhkaW0oZGYuY2x1c3RlcjAxKVsxXSwgZGltKGRmLmNsdXN0ZXIwMilbMV0sIGRpbShkZi5jbHVzdGVyMDMpWzFdKQogIGJhcnBsb3QoZGYuY2x1c3RlcnMuZGltLAogICAgICAgICAgbmFtZXMuYXJnID0gYygiY2x1c3RlcjAxIiwgImNsdXN0ZXIwMiIsICJjbHVzdGVyMDMiKSwKICAgICAgICAgIGNvbCA9ICJzdGVlbGJsdWUxIikKfQpgYGAKCiMjIyMgRGlzdHJpYnVjacOzbiBkZSBsb3MgZGF0b3MKCmBgYHtyIGZpZy5oZWlnaHQ9N30KaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMykKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTV9CmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDMpCmBgYAoKIyMjIExvY2FsaXphY2nDs24gZ2VvZ3LDoWZpY2EgZGUgbGFzIGVzdGFjaW9uZXMgZGUgbWVkaWRhIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CiMgQWdydXBhIHBvciBsb25naXR1ZCB5IGxhdGl0dWQgcGFyYSByZWxsZW5hciBlbCBtYXBhIGNvbiBtZW5vcyBkYXRvcy4KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXIwMS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAxKQogIGRmLmNsdXN0ZXIwMi5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAyKQogIGRmLmNsdXN0ZXIwMy5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAzKQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAxLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAyLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAzLmdyb3VwZWQpCmBgYAoKIyMgVmlzdWFsaXphY2nDs24gZGUgNCBjbMO6c3RlcmVzOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBwbG90KGhhYywgaGFuZz0tMSwgbGFiZWxzPUYpCiAgcmVjdC5oY2x1c3QoaGFjLCBrPTQpCn0KYGBgCgojIyMgVmlzdWFsaXphY2nDs24gZGUgbG9zIGNsw7pzdGVycyBlbiBlbCBtYXBhCgpBIHF1w6kgY2zDunN0ZXIgcGVydGVuZWNlIGNhZGEgbm9kbyBkZWwgbWFwYSBkZSBrb2hvbmVuOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBncm91cHMgPC0gY3V0cmVlKGhhYywgaz00KQogIHBsb3QobW9kZWwsIHR5cGU9Im1hcHBpbmciLAogICAgYmdjb2w9Yygic3RlZWxibHVlMSIsInNpZW5uYTEiLCJ5ZWxsb3dncmVlbiIsInJlZCIsImJsdWUiLCJ5ZWxsb3ciLCJwdXJwbGUiLCJncmVlbiIsIndoaXRlIiwiIzFmNzdiNCIsICcjZmY3ZjBlJywgJyMyY2EwMmMnLCAnI2Q2MjcyOCcsICcjOTQ2N2JkJywgJyM4YzU2NGInLCAnI2UzNzdjMicpW2dyb3Vwc10sCiAgICBzaGFwZSA9ICJzdHJhaWdodCIsIGxhYmVscyA9ICIiKQogIGFkZC5jbHVzdGVyLmJvdW5kYXJpZXMobW9kZWwsIGNsdXN0ZXJpbmc9Z3JvdXBzKQp9CmBgYAoKIyMjIEFuw6FsaXNpcyBkZSBsYXMgb2JzZXJ2YWNpb25lcyBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBBc2lnbmFtb3MgYSBjYWRhIHJlZ2lzdHJvIHN1IGNsw7pzdGVyCiAgZGYkY2x1c3RlciA8LSBncm91cHNbbW9kZWwkdW5pdC5jbGFzc2lmXQp9CmBgYAoKTnVldm9zIGRhdGFmcmFtZXMgcG9yIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBDcmVvIG51ZXZvcyBkYXRhZnJhbWVzLCB1bm8gcG9yIGNhZGEgY2zDunN0ZXIuCiAgZGYuY2x1c3RlcjAxIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MSkKICBkZi5jbHVzdGVyMDIgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0yKQogIGRmLmNsdXN0ZXIwMyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTMpCiAgZGYuY2x1c3RlcjA0IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NCkKCiAgIyBFeHRyYWlnbyBkZWwgZGF0YWZyYW1lIGxhcyBmZWF0dXJlcy4KICBkZi5jbHVzdGVyMDEgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAyIDwtIHNlbGVjdChkZi5jbHVzdGVyMDIsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMyA8LSBzZWxlY3QoZGYuY2x1c3RlcjAzLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDQgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNCwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDQpCmBgYAoKIyMjIyBOw7ptZXJvIGRlIGVsZW1lbnRvcyBlbiBjYWRhIGNsw7pzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXJzLmRpbSA8LSBjKGRpbShkZi5jbHVzdGVyMDEpWzFdLCBkaW0oZGYuY2x1c3RlcjAyKVsxXSwgZGltKGRmLmNsdXN0ZXIwMylbMV0sIGRpbShkZi5jbHVzdGVyMDQpWzFdKQogIGJhcnBsb3QoZGYuY2x1c3RlcnMuZGltLAogICAgICAgICAgbmFtZXMuYXJnID0gYygiY2x1c3RlcjAxIiwgImNsdXN0ZXIwMiIsICJjbHVzdGVyMDMiLCAiY2x1c3RlcjA0IiksCiAgICAgICAgICBjb2wgPSAic3RlZWxibHVlMSIpCn0KYGBgCgojIyMjIERpc3RyaWJ1Y2nDs24gZGUgbG9zIGRhdG9zCgpgYGB7ciBmaWcuaGVpZ2h0PTd9CmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNCkKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTV9CmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNCkKYGBgCgojIyMgTG9jYWxpemFjacOzbiBnZW9ncsOhZmljYSBkZSBsYXMgZXN0YWNpb25lcyBkZSBtZWRpZGEgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KIyBBZ3J1cGEgcG9yIGxvbmdpdHVkIHkgbGF0aXR1ZCBwYXJhIHJlbGxlbmFyIGVsIG1hcGEgY29uIG1lbm9zIGRhdG9zLgppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcjAxLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDEpCiAgZGYuY2x1c3RlcjAyLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDIpCiAgZGYuY2x1c3RlcjAzLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDMpCiAgZGYuY2x1c3RlcjA0Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDQpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDEuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDIuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDMuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDQuZ3JvdXBlZCkKYGBgCgojIyBWaXN1YWxpemFjacOzbiBkZSA1IGNsw7pzdGVyZXM6CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIHBsb3QoaGFjLCBoYW5nPS0xLCBsYWJlbHM9RikKICByZWN0LmhjbHVzdChoYWMsIGs9NSkKfQpgYGAKCiMjIyBWaXN1YWxpemFjacOzbiBkZSBsb3MgY2zDunN0ZXJzIGVuIGVsIG1hcGEKCkEgcXXDqSBjbMO6c3RlciBwZXJ0ZW5lY2UgY2FkYSBub2RvIGRlbCBtYXBhIGRlIGtvaG9uZW46CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGdyb3VwcyA8LSBjdXRyZWUoaGFjLCBrPTUpCiAgcGxvdChtb2RlbCwgdHlwZT0ibWFwcGluZyIsCiAgICBiZ2NvbD1jKCJzdGVlbGJsdWUxIiwic2llbm5hMSIsInllbGxvd2dyZWVuIiwicmVkIiwiYmx1ZSIsInllbGxvdyIsInB1cnBsZSIsImdyZWVuIiwid2hpdGUiLCIjMWY3N2I0IiwgJyNmZjdmMGUnLCAnIzJjYTAyYycsICcjZDYyNzI4JywgJyM5NDY3YmQnLCAnIzhjNTY0YicsICcjZTM3N2MyJylbZ3JvdXBzXSwKICAgIHNoYXBlID0gInN0cmFpZ2h0IiwgbGFiZWxzID0gIiIpCiAgYWRkLmNsdXN0ZXIuYm91bmRhcmllcyhtb2RlbCwgY2x1c3RlcmluZz1ncm91cHMpCn0KYGBgCgojIyMgQW7DoWxpc2lzIGRlIGxhcyBvYnNlcnZhY2lvbmVzIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICAjIEFzaWduYW1vcyBhIGNhZGEgcmVnaXN0cm8gc3UgY2zDunN0ZXIKICBkZiRjbHVzdGVyIDwtIGdyb3Vwc1ttb2RlbCR1bml0LmNsYXNzaWZdCn0KYGBgCgpOdWV2b3MgZGF0YWZyYW1lcyBwb3IgY2x1c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICAjIENyZW8gbnVldm9zIGRhdGFmcmFtZXMsIHVubyBwb3IgY2FkYSBjbMO6c3Rlci4KICBkZi5jbHVzdGVyMDEgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0xKQogIGRmLmNsdXN0ZXIwMiA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTIpCiAgZGYuY2x1c3RlcjAzIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MykKICBkZi5jbHVzdGVyMDQgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT00KQogIGRmLmNsdXN0ZXIwNSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTUpCgogICMgRXh0cmFpZ28gZGVsIGRhdGFmcmFtZSBsYXMgZmVhdHVyZXMuCiAgZGYuY2x1c3RlcjAxIDwtIHNlbGVjdChkZi5jbHVzdGVyMDEsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMiA8LSBzZWxlY3QoZGYuY2x1c3RlcjAyLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDMgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMywgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA0IDwtIHNlbGVjdChkZi5jbHVzdGVyMDQsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNSA8LSBzZWxlY3QoZGYuY2x1c3RlcjA1LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDUpCmBgYAoKIyMjIyBOw7ptZXJvIGRlIGVsZW1lbnRvcyBlbiBjYWRhIGNsw7pzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXJzLmRpbSA8LSBjKGRpbShkZi5jbHVzdGVyMDEpWzFdLCBkaW0oZGYuY2x1c3RlcjAyKVsxXSwgZGltKGRmLmNsdXN0ZXIwMylbMV0sIGRpbShkZi5jbHVzdGVyMDQpWzFdLCBkaW0oZGYuY2x1c3RlcjA1KVsxXSkKICBiYXJwbG90KGRmLmNsdXN0ZXJzLmRpbSwKICAgICAgICAgIG5hbWVzLmFyZyA9IGMoImNsdXN0ZXIwMSIsICJjbHVzdGVyMDIiLCAiY2x1c3RlcjAzIiwgImNsdXN0ZXIwNCIsICJjbHVzdGVyMDUiKSwKICAgICAgICAgIGNvbCA9ICJzdGVlbGJsdWUxIikKfQpgYGAKCiMjIyMgRGlzdHJpYnVjacOzbiBkZSBsb3MgZGF0b3MKCmBgYHtyIGZpZy5oZWlnaHQ9N30KaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDUpCmBgYAoKYGBge3IgZmlnLmhlaWdodD01fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNSkKYGBgCgojIyMgTG9jYWxpemFjacOzbiBnZW9ncsOhZmljYSBkZSBsYXMgZXN0YWNpb25lcyBkZSBtZWRpZGEgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KIyBBZ3J1cGEgcG9yIGxvbmdpdHVkIHkgbGF0aXR1ZCBwYXJhIHJlbGxlbmFyIGVsIG1hcGEgY29uIG1lbm9zIGRhdG9zLgppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcjAxLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDEpCiAgZGYuY2x1c3RlcjAyLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDIpCiAgZGYuY2x1c3RlcjAzLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDMpCiAgZGYuY2x1c3RlcjA0Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDQpCiAgZGYuY2x1c3RlcjA1Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDUpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDEuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDIuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDMuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDQuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDUuZ3JvdXBlZCkKYGBgCgojIyBWaXN1YWxpemFjacOzbiBkZSA2IGNsw7pzdGVyZXM6CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIHBsb3QoaGFjLCBoYW5nPS0xLCBsYWJlbHM9RikKICByZWN0LmhjbHVzdChoYWMsIGs9NikKfQpgYGAKCiMjIyBWaXN1YWxpemFjacOzbiBkZSBsb3MgY2zDunN0ZXJzIGVuIGVsIG1hcGEKCkEgcXXDqSBjbMO6c3RlciBwZXJ0ZW5lY2UgY2FkYSBub2RvIGRlbCBtYXBhIGRlIGtvaG9uZW46CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGdyb3VwcyA8LSBjdXRyZWUoaGFjLCBrPTYpCiAgcGxvdChtb2RlbCwgdHlwZT0ibWFwcGluZyIsCiAgICBiZ2NvbD1jKCJzdGVlbGJsdWUxIiwic2llbm5hMSIsInllbGxvd2dyZWVuIiwicmVkIiwiYmx1ZSIsInllbGxvdyIsInB1cnBsZSIsImdyZWVuIiwid2hpdGUiLCIjMWY3N2I0IiwgJyNmZjdmMGUnLCAnIzJjYTAyYycsICcjZDYyNzI4JywgJyM5NDY3YmQnLCAnIzhjNTY0YicsICcjZTM3N2MyJylbZ3JvdXBzXSwKICAgIHNoYXBlID0gInN0cmFpZ2h0IiwgbGFiZWxzID0gIiIpCiAgYWRkLmNsdXN0ZXIuYm91bmRhcmllcyhtb2RlbCwgY2x1c3RlcmluZz1ncm91cHMpCn0KYGBgCgojIyMgQW7DoWxpc2lzIGRlIGxhcyBvYnNlcnZhY2lvbmVzIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICAjIEFzaWduYW1vcyBhIGNhZGEgcmVnaXN0cm8gc3UgY2zDunN0ZXIKICBkZiRjbHVzdGVyIDwtIGdyb3Vwc1ttb2RlbCR1bml0LmNsYXNzaWZdCn0KYGBgCgpOdWV2b3MgZGF0YWZyYW1lcyBwb3IgY2x1c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICAjIENyZW8gbnVldm9zIGRhdGFmcmFtZXMsIHVubyBwb3IgY2FkYSBjbMO6c3Rlci4KICBkZi5jbHVzdGVyMDEgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0xKQogIGRmLmNsdXN0ZXIwMiA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTIpCiAgZGYuY2x1c3RlcjAzIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MykKICBkZi5jbHVzdGVyMDQgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT00KQogIGRmLmNsdXN0ZXIwNSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTUpCiAgZGYuY2x1c3RlcjA2IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NikKCiAgIyBFeHRyYWlnbyBkZWwgZGF0YWZyYW1lIGxhcyBmZWF0dXJlcy4KICBkZi5jbHVzdGVyMDEgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAyIDwtIHNlbGVjdChkZi5jbHVzdGVyMDIsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMyA8LSBzZWxlY3QoZGYuY2x1c3RlcjAzLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDQgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNCwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA1IDwtIHNlbGVjdChkZi5jbHVzdGVyMDUsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNiA8LSBzZWxlY3QoZGYuY2x1c3RlcjA2LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDUpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA2KQpgYGAKCiMjIyMgTsO6bWVybyBkZSBlbGVtZW50b3MgZW4gY2FkYSBjbMO6c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVycy5kaW0gPC0gYyhkaW0oZGYuY2x1c3RlcjAxKVsxXSwgZGltKGRmLmNsdXN0ZXIwMilbMV0sIGRpbShkZi5jbHVzdGVyMDMpWzFdLCBkaW0oZGYuY2x1c3RlcjA0KVsxXSwgZGltKGRmLmNsdXN0ZXIwNSlbMV0sIGRpbShkZi5jbHVzdGVyMDYpWzFdKQogIGJhcnBsb3QoZGYuY2x1c3RlcnMuZGltLAogICAgICAgICAgbmFtZXMuYXJnID0gYygiY2x1c3RlcjAxIiwgImNsdXN0ZXIwMiIsICJjbHVzdGVyMDMiLCAiY2x1c3RlcjA0IiwgImNsdXN0ZXIwNSIsICJjbHVzdGVyMDYiKSwKICAgICAgICAgIGNvbCA9ICJzdGVlbGJsdWUxIikKfQpgYGAKCiMjIyMgRGlzdHJpYnVjacOzbiBkZSBsb3MgZGF0b3MKCmBgYHtyIGZpZy5oZWlnaHQ9N30KaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDUpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNikKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTV9CmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA1KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDYpCmBgYAoKIyMjIExvY2FsaXphY2nDs24gZ2VvZ3LDoWZpY2EgZGUgbGFzIGVzdGFjaW9uZXMgZGUgbWVkaWRhIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CiMgQWdydXBhIHBvciBsb25naXR1ZCB5IGxhdGl0dWQgcGFyYSByZWxsZW5hciBlbCBtYXBhIGNvbiBtZW5vcyBkYXRvcy4KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXIwMS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAxKQogIGRmLmNsdXN0ZXIwMi5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAyKQogIGRmLmNsdXN0ZXIwMy5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAzKQogIGRmLmNsdXN0ZXIwNC5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA0KQogIGRmLmNsdXN0ZXIwNS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA1KQogIGRmLmNsdXN0ZXIwNi5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA2KQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAxLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAyLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAzLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA0Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA1Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA2Lmdyb3VwZWQpCmBgYAoKIyMgVmlzdWFsaXphY2nDs24gZGUgOCBjbMO6c3RlcmVzOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBwbG90KGhhYywgaGFuZz0tMSwgbGFiZWxzPUYpCiAgcmVjdC5oY2x1c3QoaGFjLCBrPTgpCn0KYGBgCgojIyMgVmlzdWFsaXphY2nDs24gZGUgbG9zIGNsw7pzdGVycyBlbiBlbCBtYXBhCgpBIHF1w6kgY2zDunN0ZXIgcGVydGVuZWNlIGNhZGEgbm9kbyBkZWwgbWFwYSBkZSBrb2hvbmVuOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBncm91cHMgPC0gY3V0cmVlKGhhYywgaz04KQogIHBsb3QobW9kZWwsIHR5cGU9Im1hcHBpbmciLAogICAgYmdjb2w9Yygic3RlZWxibHVlMSIsInNpZW5uYTEiLCJ5ZWxsb3dncmVlbiIsInJlZCIsImJsdWUiLCJ5ZWxsb3ciLCJwdXJwbGUiLCJncmVlbiIsIndoaXRlIiwiIzFmNzdiNCIsICcjZmY3ZjBlJywgJyMyY2EwMmMnLCAnI2Q2MjcyOCcsICcjOTQ2N2JkJywgJyM4YzU2NGInLCAnI2UzNzdjMicpW2dyb3Vwc10sCiAgICBzaGFwZSA9ICJzdHJhaWdodCIsIGxhYmVscyA9ICIiKQogIGFkZC5jbHVzdGVyLmJvdW5kYXJpZXMobW9kZWwsIGNsdXN0ZXJpbmc9Z3JvdXBzKQp9CmBgYAoKIyMjIEFuw6FsaXNpcyBkZSBsYXMgb2JzZXJ2YWNpb25lcyBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBBc2lnbmFtb3MgYSBjYWRhIHJlZ2lzdHJvIHN1IGNsw7pzdGVyCiAgZGYkY2x1c3RlciA8LSBncm91cHNbbW9kZWwkdW5pdC5jbGFzc2lmXQp9CmBgYAoKTnVldm9zIGRhdGFmcmFtZXMgcG9yIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBDcmVvIG51ZXZvcyBkYXRhZnJhbWVzLCB1bm8gcG9yIGNhZGEgY2zDunN0ZXIuCiAgZGYuY2x1c3RlcjAxIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MSkKICBkZi5jbHVzdGVyMDIgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0yKQogIGRmLmNsdXN0ZXIwMyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTMpCiAgZGYuY2x1c3RlcjA0IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NCkKICBkZi5jbHVzdGVyMDUgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT01KQogIGRmLmNsdXN0ZXIwNiA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTYpCiAgZGYuY2x1c3RlcjA3IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NykKICBkZi5jbHVzdGVyMDggPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT04KQoKICAjIEV4dHJhaWdvIGRlbCBkYXRhZnJhbWUgbGFzIGZlYXR1cmVzLgogIGRmLmNsdXN0ZXIwMSA8LSBzZWxlY3QoZGYuY2x1c3RlcjAxLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDIgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMiwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAzIDwtIHNlbGVjdChkZi5jbHVzdGVyMDMsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNCA8LSBzZWxlY3QoZGYuY2x1c3RlcjA0LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDUgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA2IDwtIHNlbGVjdChkZi5jbHVzdGVyMDYsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNyA8LSBzZWxlY3QoZGYuY2x1c3RlcjA3LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDggPC0gc2VsZWN0KGRmLmNsdXN0ZXIwOCwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA1KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNikKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDcpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA4KQpgYGAKCiMjIyMgTsO6bWVybyBkZSBlbGVtZW50b3MgZW4gY2FkYSBjbMO6c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVycy5kaW0gPC0gYyhkaW0oZGYuY2x1c3RlcjAxKVsxXSwgZGltKGRmLmNsdXN0ZXIwMilbMV0sIGRpbShkZi5jbHVzdGVyMDMpWzFdLCBkaW0oZGYuY2x1c3RlcjA0KVsxXSwgZGltKGRmLmNsdXN0ZXIwNSlbMV0sIGRpbShkZi5jbHVzdGVyMDYpWzFdLCBkaW0oZGYuY2x1c3RlcjA3KVsxXSwgZGltKGRmLmNsdXN0ZXIwOClbMV0pCiAgYmFycGxvdChkZi5jbHVzdGVycy5kaW0sCiAgICAgICAgICBuYW1lcy5hcmcgPSBjKCJjbHVzdGVyMDEiLCAiY2x1c3RlcjAyIiwgImNsdXN0ZXIwMyIsICJjbHVzdGVyMDQiLCAiY2x1c3RlcjA1IiwgImNsdXN0ZXIwNiIsICJjbHVzdGVyMDciLCAiY2x1c3RlcjA4IiksCiAgICAgICAgICBjb2wgPSAic3RlZWxibHVlMSIpCn0KYGBgCgojIyMjIERpc3RyaWJ1Y2nDs24gZGUgbG9zIGRhdG9zCgpgYGB7ciBmaWcuaGVpZ2h0PTd9CmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA1KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDYpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA4KQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9NX0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDUpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA3KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDgpCmBgYAoKIyMjIExvY2FsaXphY2nDs24gZ2VvZ3LDoWZpY2EgZGUgbGFzIGVzdGFjaW9uZXMgZGUgbWVkaWRhIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CiMgQWdydXBhIHBvciBsb25naXR1ZCB5IGxhdGl0dWQgcGFyYSByZWxsZW5hciBlbCBtYXBhIGNvbiBtZW5vcyBkYXRvcy4KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXIwMS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAxKQogIGRmLmNsdXN0ZXIwMi5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAyKQogIGRmLmNsdXN0ZXIwMy5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAzKQogIGRmLmNsdXN0ZXIwNC5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA0KQogIGRmLmNsdXN0ZXIwNS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA1KQogIGRmLmNsdXN0ZXIwNi5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA2KQogIGRmLmNsdXN0ZXIwNy5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA3KQogIGRmLmNsdXN0ZXIwOC5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA4KQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAxLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAyLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAzLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA0Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA1Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA2Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA3Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA4Lmdyb3VwZWQpCmBgYAoKIyMgVmlzdWFsaXphY2nDs24gZGUgMTAgY2zDunN0ZXJlczoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgcGxvdChoYWMsIGhhbmc9LTEsIGxhYmVscz1GKQogIHJlY3QuaGNsdXN0KGhhYywgaz0xMCkKfQpgYGAKCiMjIyBWaXN1YWxpemFjacOzbiBkZSBsb3MgY2zDunN0ZXJzIGVuIGVsIG1hcGEKCkEgcXXDqSBjbMO6c3RlciBwZXJ0ZW5lY2UgY2FkYSBub2RvIGRlbCBtYXBhIGRlIGtvaG9uZW46CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGdyb3VwcyA8LSBjdXRyZWUoaGFjLCBrPTEwKQogIHBsb3QobW9kZWwsIHR5cGU9Im1hcHBpbmciLAogICAgYmdjb2w9Yygic3RlZWxibHVlMSIsInNpZW5uYTEiLCJ5ZWxsb3dncmVlbiIsInJlZCIsImJsdWUiLCJ5ZWxsb3ciLCJwdXJwbGUiLCJncmVlbiIsIndoaXRlIiwiIzFmNzdiNCIsICcjZmY3ZjBlJywgJyMyY2EwMmMnLCAnI2Q2MjcyOCcsICcjOTQ2N2JkJywgJyM4YzU2NGInLCAnI2UzNzdjMicpW2dyb3Vwc10sCiAgICBzaGFwZSA9ICJzdHJhaWdodCIsIGxhYmVscyA9ICIiKQogIGFkZC5jbHVzdGVyLmJvdW5kYXJpZXMobW9kZWwsIGNsdXN0ZXJpbmc9Z3JvdXBzKQp9CmBgYAoKIyMjIEFuw6FsaXNpcyBkZSBsYXMgb2JzZXJ2YWNpb25lcyBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBBc2lnbmFtb3MgYSBjYWRhIHJlZ2lzdHJvIHN1IGNsw7pzdGVyCiAgZGYkY2x1c3RlciA8LSBncm91cHNbbW9kZWwkdW5pdC5jbGFzc2lmXQp9CmBgYAoKTnVldm9zIGRhdGFmcmFtZXMgcG9yIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBDcmVvIG51ZXZvcyBkYXRhZnJhbWVzLCB1bm8gcG9yIGNhZGEgY2zDunN0ZXIuCiAgZGYuY2x1c3RlcjAxIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MSkKICBkZi5jbHVzdGVyMDIgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0yKQogIGRmLmNsdXN0ZXIwMyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTMpCiAgZGYuY2x1c3RlcjA0IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NCkKICBkZi5jbHVzdGVyMDUgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT01KQogIGRmLmNsdXN0ZXIwNiA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTYpCiAgZGYuY2x1c3RlcjA3IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NykKICBkZi5jbHVzdGVyMDggPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT04KQogIGRmLmNsdXN0ZXIwOSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTkpCiAgZGYuY2x1c3RlcjEwIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MTApCgogICMgRXh0cmFpZ28gZGVsIGRhdGFmcmFtZSBsYXMgZmVhdHVyZXMuCiAgZGYuY2x1c3RlcjAxIDwtIHNlbGVjdChkZi5jbHVzdGVyMDEsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMiA8LSBzZWxlY3QoZGYuY2x1c3RlcjAyLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDMgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMywgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA0IDwtIHNlbGVjdChkZi5jbHVzdGVyMDQsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNSA8LSBzZWxlY3QoZGYuY2x1c3RlcjA1LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDYgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNiwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA3IDwtIHNlbGVjdChkZi5jbHVzdGVyMDcsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwOCA8LSBzZWxlY3QoZGYuY2x1c3RlcjA4LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDkgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwOSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjEwIDwtIHNlbGVjdChkZi5jbHVzdGVyMTAsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNSkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDYpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA3KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwOCkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDkpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjEwKQpgYGAKCiMjIyMgTsO6bWVybyBkZSBlbGVtZW50b3MgZW4gY2FkYSBjbMO6c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVycy5kaW0gPC0gYyhkaW0oZGYuY2x1c3RlcjAxKVsxXSwgZGltKGRmLmNsdXN0ZXIwMilbMV0sIGRpbShkZi5jbHVzdGVyMDMpWzFdLCBkaW0oZGYuY2x1c3RlcjA0KVsxXSwgZGltKGRmLmNsdXN0ZXIwNSlbMV0sIGRpbShkZi5jbHVzdGVyMDYpWzFdLCBkaW0oZGYuY2x1c3RlcjA3KVsxXSwgZGltKGRmLmNsdXN0ZXIwOClbMV0sIGRpbShkZi5jbHVzdGVyMDkpWzFdLCBkaW0oZGYuY2x1c3RlcjEwKVsxXSkKICBiYXJwbG90KGRmLmNsdXN0ZXJzLmRpbSwKICAgICAgICAgIG5hbWVzLmFyZyA9IGMoImNsdXN0ZXIwMSIsICJjbHVzdGVyMDIiLCAiY2x1c3RlcjAzIiwgImNsdXN0ZXIwNCIsICJjbHVzdGVyMDUiLCAiY2x1c3RlcjA2IiwgImNsdXN0ZXIwNyIsICJjbHVzdGVyMDgiLCAiY2x1c3RlcjA5IiwgImNsdXN0ZXIxMCIpLAogICAgICAgICAgY29sID0gInN0ZWVsYmx1ZTEiKQp9CmBgYAoKIyMjIyBEaXN0cmlidWNpw7NuIGRlIGxvcyBkYXRvcwoKYGBge3IgZmlnLmhlaWdodD03fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA2KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDcpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwOCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA5KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMTApCmBgYAoKYGBge3IgZmlnLmhlaWdodD01fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA2KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDcpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwOCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA5KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMTApCmBgYAoKIyMjIExvY2FsaXphY2nDs24gZ2VvZ3LDoWZpY2EgZGUgbGFzIGVzdGFjaW9uZXMgZGUgbWVkaWRhIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CiMgQWdydXBhIHBvciBsb25naXR1ZCB5IGxhdGl0dWQgcGFyYSByZWxsZW5hciBlbCBtYXBhIGNvbiBtZW5vcyBkYXRvcy4KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXIwMS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAxKQogIGRmLmNsdXN0ZXIwMi5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAyKQogIGRmLmNsdXN0ZXIwMy5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAzKQogIGRmLmNsdXN0ZXIwNC5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA0KQogIGRmLmNsdXN0ZXIwNS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA1KQogIGRmLmNsdXN0ZXIwNi5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA2KQogIGRmLmNsdXN0ZXIwNy5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA3KQogIGRmLmNsdXN0ZXIwOC5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA4KQogIGRmLmNsdXN0ZXIwOS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA5KQogIGRmLmNsdXN0ZXIxMC5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjEwKQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAxLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAyLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAzLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA0Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA1Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA2Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA3Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA4Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA5Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjEwLmdyb3VwZWQpCmBgYAo=